0

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

Qwerty
  • 1
  • You cannot encrypt with a private key, only sign. Neither can you decrypt with a public key, only verify. Therefore `RSA.Decrypt()` fails for a public key. `privateEncrypt()` works, because it does not encrypt, but creates a signature (despite the name). This function is intended for low level signing. – Topaco Jan 10 '23 at 15:36
  • @Topaco Thank you for help, I was in a hurry and tried to use it without a good understanding of the technology, and a problem occurred I guess next time I'll have to be a little more meticulous Thank you for your help! – Qwerty Jan 10 '23 at 15:53

0 Answers0