C#与C ++ ssl_connect [英] c# vs c++ ssl_connect

查看:120
本文介绍了C#与C ++ ssl_connect的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您好,我有一个使用openssl和winapi套接字的c ++应用程序,代码如下:

Hello i have a c++ application that uses openssl and winapi sockets, and the code looks like this:

sock = socket(AF_INET, SOCK_STREAM, 0);
    if (connect(my_sock, (struct sockaddr*)&dest_addr, sizeof(dest_addr))==0) {
            WSAIoctl(my_sock, SIO_KEEPALIVE_VALS, &alive, sizeof(alive),NULL, 0, &dwSize, NULL, NULL);
        }
    }
.....

SSL_load_error_strings();
SSL_library_init();


    ctx = SSL_CTX_new(SSLv23_client_method());
    if(!ctx) 
    {
       return false;
    }
        ssl = SSL_new(ctx);
        SSL_CTX_free(ctx);
        if(!ssl) 
        {
                return false;
        }
        SSL_set_fd(ssl, (int)sock); //making the socket use ssl mode
        result = SSL_connect(ssl);

我在此c ++应用程序中使用了静态ssl库,我是从此处下载的

Im using the static ssl libraries with this c++ application, which i downloaded from here

一切正常,并且ssl_connect返回1.但是我需要做的是使用c#重写此代码.所以我尝试了,而C#代码看起来像这样:

Everything works fine, and ssl_connect returns 1. But what i need to do is re-write this code using c#. So i tried, and c# code looks like this:

    [DllImport("ssleay32.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SSL_read")]
    public static extern int SSL_Read(IntPtr ssl, ref byte[] buf, int num);

    [DllImport("ssleay32.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SSL_write")]
    public static extern int SSL_Write(IntPtr ssl, byte[] buf, int num);

    [DllImport("ssleay32.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SSL_set_fd")]
    extern public static int SSL_set_fd(IntPtr ssl, int fd);

    [DllImport("ssleay32.dll", CallingConvention= CallingConvention.Cdecl, EntryPoint = "SSL_CTX_new")]
    extern public static IntPtr SSL_CTX_new(IntPtr method);

    [DllImport("ssleay32.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SSL_new")]
    extern public static IntPtr SSL_new(IntPtr ctx);

    [DllImport("ssleay32.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SSL_connect")]
    extern public static int SSL_connect(IntPtr ssl);

    [DllImport("ssleay32.dll",CallingConvention= CallingConvention.Cdecl, EntryPoint = "SSL_load_error_strings")]
    extern public static void SSL_load_error_strings();

    [DllImport("ssleay32.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SSL_library_init")]
    extern public static int SSL_library_init();

    [DllImport("ssleay32.dll",CallingConvention= CallingConvention.Cdecl, EntryPoint = "SSLeay_add_all_algorithms")]
    extern public static int SSLeay_add_all_algorithms();

    [DllImport("ssleay32.dll",CallingConvention= CallingConvention.Cdecl, EntryPoint = "SSLv23_client_method")]
    extern public static IntPtr SSLv23_client_method();

    [DllImport("ssleay32.dll",CallingConvention= CallingConvention.Cdecl, EntryPoint = "SSLv3_client_method")]
    extern public static IntPtr SSLv3_client_method();


    [DllImport("ssleay32.dll",CallingConvention= CallingConvention.Cdecl, EntryPoint = "SSL_CTX_free")]
    extern public static void SSL_CTX_free(IntPtr ctx);

    [DllImport("ssleay32.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SSL_free")]
    extern public static void SSL_free(IntPtr ssl);

    [DllImport("ssleay32.dll",CallingConvention= CallingConvention.Cdecl, EntryPoint = "SSL_get_error")]
    extern public static int SSL_get_error(IntPtr ssl, int ret);

    [DllImport("ssleay32.dll",CallingConvention= CallingConvention.Cdecl, EntryPoint = "  SSL_CTX_set_mode")]
    extern public static long SSL_CTX_set_mode(IntPtr ctx, long mode);


    [DllImport("libeay32", CallingConvention = CallingConvention.Cdecl, EntryPoint = "OPENSSL_add_all_algorithms_noconf")]
    extern public static void OpenSSL_add_all_algorithms();

    [DllImport("libeay32", CallingConvention = CallingConvention.Cdecl, EntryPoint = "ERR_get_error")]
    extern public static int ERR_get_error();

    [DllImport("ssleay32.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SSL_CTX_ctrl")]
    public extern static int SSL_CTX_ctrl(IntPtr ctx, int cmd, int arg, IntPtr parg);


    [DllImport("ssleay32.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SSLv23_method")]
    public extern static IntPtr SSLv23_method();



public bool Ssl_Init()
{

        SSL_load_error_strings();           
        OpenSSL_add_all_algorithms();
        SSL_library_init();

         IntPtr method = SSLv23_client_method();

         IntPtr ctx = SSL_CTX_new(method);

         if (ctx == IntPtr.Zero)
         {
              return false;
         }

         _ssl = SSL_new(ctx);
         if (_ssl == IntPtr.Zero)
         {
            return false;
         }

         int val = SSL_set_fd(_ssl, this.socket.Handle.ToInt32()); //always returns 1
         int result = SSL_connect(_ssl);
         if(result!=1) return false;
         SSL_CTX_free(ctx);
         Ssl_Enabled.Set();
         return true;
}

我的c#套接字的创建方式如下:

My c# socket is created like so:

 socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

 this.socket.Connect(host,port);

 socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, 1000);

我总是在我的C#代码中获得SSL_Connect = 0,并且SSL_get_error()= 5(error_syscall).所以基本上我的问题是,将.net套接字与openssl一起使用可能有什么问题? (因为c ++应用程序可以与相同类型的代码完美协作).

I always get SSL_Connect = 0 in my c# code, with SSL_get_error() = 5 (error_syscall). So basically my question is, what's might be wrong with using .net socket with openssl? (because c++ application works perfectly with the same kind of code).

更新:我尝试使用OPENSSL_add_all_algorithms_conf,但似乎没有任何改变...我求您了!

Update: I tried to use OPENSSL_add_all_algorithms_conf but it seems it doesn't change anything... I'm begging you for help!!

推荐答案

据我所知,System.Net.Sockets类不支持SSL.经过研究,它看起来像在System.Net.Security和System.Security.Authentication ...

As far as I can tell, the System.Net.Sockets class doesn't have support for SSL. After some research, it looks like it's in System.Net.Security and System.Security.Authentication...

这里是指向MS示例的链接... http://msdn. microsoft.com/en-us/library/system.net.security.sslstream(v=vs.110).aspx

Here's a link to an MS example... http://msdn.microsoft.com/en-us/library/system.net.security.sslstream(v=vs.110).aspx

此示例向服务器发送一条消息,然后断开连接.我写了一个类似的(非SSL)客户端,它是全双工(发送和接收异步).您可能可以使用某些MS示例修改我的示例以通过SSL进行通信.

This example sends one message to the server and then disconnects. I wrote a similar (non-SSL) client that is Full Duplex (send and received async). You can probably adapt my example to communicate over SSL using some of the MS example.

这是...希望它能帮助...让我知道您是否将其调整为适用于SSL,因为我可能需要做同样的事情.

Here it is...Hope it helps...let me know if you adapt it for SSL as I'll likely need to do the same.

using System;
using System.Text;
using System.Net.Sockets;
using System.Collections.Generic;

namespace MyNamespace.Utilities
{
        public class StateObject{
            public Socket workSocket = null;
            public const int BUFFER_SIZE = 1024;
            public byte[] buffer = new byte[BUFFER_SIZE];
            //public StringBuilder message = new StringBuilder();
        }

        public class FullDuplexSocket : IDisposable
        {
            public event NewMessageHandler OnMessageReceived;
            public delegate void NewMessageHandler(string Message);
            public event DisconnectHandler OnDisconnect;
            public delegate void DisconnectHandler(string Reason);

            private Socket _socket;
            private bool _useASCII = true;
            private string _remoteServerIp = "";
            private int _port = 0;
            private bool _allowRetry = true;

            /// <summary>
            /// Constructer of a full duplex client socket.   The consumer should immedately define 
            /// and event handler for the OnMessageReceived event after construction has completed.
            /// </summary>
            /// <param name="RemoteServerIp">The remote Ip address of the server.</param>
            /// <param name="Port">The port that will used to transfer/receive messages to/from the remote IP.</param>
            /// <param name="UseASCII">The character type to encode/decode messages.  Defaulted to use ASCII, but setting the value to false will encode/decode messages in UNICODE.</param>
            public FullDuplexSocket(string RemoteServerIp, int Port, bool UseASCII = true)
            {
                _useASCII = UseASCII;
                _remoteServerIp = RemoteServerIp;
                _port = Port;

                Initialize();
            }

            private void Initialize()
            {
                try //to create the socket and connect
                {
                    _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    _socket.Connect(_remoteServerIp, _port);
                }
                catch (Exception e)
                {
                    throw new Exception("Unable to connect to the remote Ip.", e);
                }

                try //to listen to the socket
                {
                    StateObject stateObject = new StateObject();
                    stateObject.workSocket = _socket;

                    _socket.BeginReceive
                        (
                            stateObject.buffer, //Buffer to load in our state object
                            0, //Start at the first position in the byte array
                            StateObject.BUFFER_SIZE, //only load up to the max per read
                            0, //Set socket flags here if necessary 
                            new AsyncCallback(ReadFromSocket), //Who to call when data arrives
                            stateObject //state object to use when data arrives
                        );
                    _allowRetry = true;
                }
                catch (Exception e)
                {
                    throw new Exception("Unable to start listening to the socket.", e);
                }
            }


            /// <summary>
            /// This will read the bytes from the socket, convert the bytes to a string and fire the OnMessageReceived event.
            /// If the socket is forcibly closed, the OnDisconnect event will be fired.   This happens when the other side of
            /// the socket connection on the remote Ip is no longer available.
            /// </summary>
            /// <param name="asyncResult"></param>
            public void ReadFromSocket(IAsyncResult asyncResult)
            {
                StateObject stateObject = (StateObject)asyncResult.AsyncState; //pull out the state object
                int bytesReceived = 0;

                try //to receive the message.
                {
                    bytesReceived = stateObject.workSocket.EndReceive(asyncResult); 
                }
                catch (Exception e)  //Exception will occur if connection was forcibly closed.
                {
                    RaiseOnDisconnect(e.Message);
                    return;
                }

                if (bytesReceived > 0)
                {
                    RaiseOnMessageReceived
                        (
                            _useASCII ?
                                Encoding.ASCII.GetString(stateObject.buffer, 0, bytesReceived) :
                                Encoding.Unicode.GetString(stateObject.buffer, 0, bytesReceived)
                        );

                    try  //The BeginRecieve can file due to network issues.   _allowRetry allows a single failure between successful connections.
                    {
                        if (_allowRetry)
                        {
                            stateObject.workSocket.BeginReceive
                                (
                                    stateObject.buffer, //Buffer to load in our state object
                                    0, //Start at the first position in the byte array
                                    StateObject.BUFFER_SIZE, //only load up to the max per read
                                    0, //Set socket flags here if necessary 
                                    new AsyncCallback(ReadFromSocket), //Who to call when data arrives
                                    stateObject //state object to use when data arrives
                                );
                        }
                    }
                    catch
                    {
                        _allowRetry = false;
                    }
                }
                else
                {
                    stateObject.workSocket.Close();
                    RaiseOnDisconnect("Socket closed normally.");
                    return;
                }
            }
            /// <summary>
            /// Broadcast a message to the IP/Port.  Consumer should handle any exceptions thrown by the socket.
            /// </summary>
            /// <param name="Message">The message to be sent will be encoded using the character set defined during construction.</param>
            public void Send(string Message)
            {
                //all messages are terminated with /r/n
                Message += Environment.NewLine;

                byte[] bytesToSend = _useASCII ?
                    Encoding.ASCII.GetBytes(Message) :
                    Encoding.Unicode.GetBytes(Message);

                int bytesSent = _socket.Send(bytesToSend);

            }

            /// <summary>
            /// Clean up the socket.
            /// </summary>
            void IDisposable.Dispose()
            {
                try
                {
                    _socket.Close();
                    RaiseOnDisconnect("Socket closed via Dispose method.");
                }
                catch { }
                try
                {
                    _socket.Dispose();
                }
                catch { }
            }


            /// <summary>
            /// This method will gracefully raise any delegated events if they exist.
            /// </summary>
            /// <param name="Message"></param>
            private void RaiseOnMessageReceived(string Message)
            {
                try //to raise delegates
                {
                    OnMessageReceived(Message);
                }
                catch { } //when none exist ignore the Object Reference Error
            }

            /// <summary>
            /// This method will gracefully raise any delegated events if they exist.
            /// </summary>
            /// <param name="Message"></param>
            private void RaiseOnDisconnect(string Message)
            {
                try //to raise delegates
                {
                    OnDisconnect(Message);
                }
                catch { } //when none exist ignore the Object Reference Error
            }

        }
}

这篇关于C#与C ++ ssl_connect的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆