OAEP Padding error occurs when C# decrypts data encrypted with RSA in NodeJS crypto module

152 Views Asked by At

I have created a C# Client and NodeJS Server that communicate with WebsocketsAnd I encrypted the message passing through the socket with RSAThe data encrypted by the client using the public key could be decrypted by the server, but the data encrypted by the server by the private key could not be decrypted by the client. and then an error occurred 'System.Security.Cryptography.CryptographicException: 'Error occurred while decoding OAEP padding.'

Client code - Form1.cs

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
using System;
using System.IO;
using System.Net.WebSockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace Something Namespace
{
    public partial class Form1: Form
    {
        private ClientWebSocket ws = new ClientWebSocket();
        public Login(string[] args)
        {
            InitializeComponent();
        }

        private async void Login_Load(object sender, EventArgs e)
        {
            RSACryptoServiceProvider RSA = ImportPublicKey("Something Public Key");
            string MessageEncrypted = Convert.ToBase64String(RSA.Encrypt(Encoding.UTF8.GetBytes("Hi I am Client"), true));
            MessageBox.Show(MessageEncrypted);
            Uri serverUri = new Uri("ws://localhost:3000/");
            await ws.ConnectAsync(serverUri, CancellationToken.None);
            ArraySegment<byte> bytesToSend = new ArraySegment<byte>(Encoding.UTF8.GetBytes(MessageEncrypted));
            await ws.SendAsync(bytesToSend, WebSocketMessageType.Text, true, CancellationToken.None);
            while (ws.State == WebSocketState.Open)
            {
                ArraySegment<byte> bytesReceived = new ArraySegment<byte>(new byte[2048]);
                WebSocketReceiveResult result = await ws.ReceiveAsync(bytesReceived, CancellationToken.None);
                string response = Encoding.UTF8.GetString(bytesReceived.Array, 0, result.Count);
                
                MessageBox.Show(response);
                if (response != "Hi I am Client")
                {
                    RSA.Decrypt(Convert.FromBase64String(response), true);
                }
            }
        }

        public static RSACryptoServiceProvider ImportPublicKey(string pem)
        {
            PemReader pr = new PemReader(new StringReader(pem));
            AsymmetricKeyParameter publicKey = (AsymmetricKeyParameter)pr.ReadObject();
            RSAParameters rsaParams = DotNetUtilities.ToRSAParameters((RsaKeyParameters)publicKey);

            RSACryptoServiceProvider csp = new RSACryptoServiceProvider();;
            csp.ImportParameters(rsaParams);
            return csp;
        }
    }
}

Server code - index.js

require('dotenv').config();
const express = require('express');

const app = express();

async function initialize() {
    // app.use(express.static(__dirname + '/public'));
    var server = await require('./server')(app);
    var ws = await require('./socket')(server);

    // bot
}

initialize();

Server code - server.js

module.exports = async (app) => {
    ...

    await loadMiddlewares();
    await loadRoutes();
    await checkDatabase();
    return await app.listen(app.get('port'), () => {
        logger.info(`${process.env.SERVER_NAME} server started on port ${app.get('port')}`);
    });
};

Server code - socket.js

const webSocket = require('ws');
const rsa = require('./modules/rsa')

module.exports = (server) => {
    const ws = new webSocket.Server({ server });

    ws.on('connection', (client, req) => {
        client.id = req.headers['sec-websocket-key'];
        ws.clients[client.id] = client;

        client.on('message', (message) => {
            switch (req.url) {
                default:
                    console.log('received: %s', message)
                    var received = rsa.privateDecrypt(String(message, 'utf8'), process.env.RSA_PRIVATE_KEY)
                    client.send(received);
                    var sent = rsa.privateEncrypt(received, process.env.RSA_PRIVATE_KEY)
                    client.send(sent);
                    console.log('sent: %s', sent);
                    break;
            }
        });

        client.on('close', (code, reason) => {
            delete ws.clients[client.id];
        });
    });

    return ws;
};

Server code - rsa.js

const crypto = require('crypto');

exports.privateEncrypt = (data, key) => {
    const buffer = Buffer.from(data);
    const encrypted = crypto.privateEncrypt(key, buffer);
    return encrypted.toString("base64");
}

exports.privateDecrypt = (data, key) => {
    const buffer = Buffer.from(data, "base64");
    const decrypted = crypto.privateDecrypt(key, buffer);
    return decrypted.toString("utf8");
}

exports.publicEncrypt = (data, key) => {
    const buffer = Buffer.from(data);
    const encrypted = crypto.publicEncrypt(key, buffer);
    return encrypted.toString("base64");
}

exports.publicDecrypt = (data, key) => {
    const buffer = Buffer.from(data, "base64");
    const decrypted = crypto.publicDecrypt(key, buffer);
    return decrypted.toString("utf8");
}

there was no problem with the value encrypted by the server then I found a post on stackoverflow with the same problem, and there it was said that UTF-8 encoding may not always return the same result so I tried using other encodings instead of UTF-8, but I cant solve this problem in my head

0

There are 0 best solutions below